#include "StdAfx.h"
#include "SimpleEvent.h"
#include "WindowsUtility.h"

namespace RoomFW {

SimpleEvent::SimpleEvent(void) :
	handle_(),
	cs_()
{
	// "Safe" constructor.
}

SimpleEvent::SimpleEvent(const SimpleEvent& rhs) :
	handle_(),
	cs_()
{
	// Don't copy critical section!
	CriticalSectionGuard g(cs_);
	CriticalSectionGuard go(rhs.cs_);
	handle_ = rhs.handle_;
}

SimpleEvent::~SimpleEvent(void)
{
	{CriticalSectionGuard g(cs_);
		handle_.reset();
	}
}

SimpleEvent& SimpleEvent::operator=(const SimpleEvent& rhs)
{
	if (&rhs != this)
	{
		// Don't copy critical section!
		{CriticalSectionGuard g(cs_);
		 CriticalSectionGuard go(rhs.cs_);
			handle_ = rhs.handle_;
		}
	}
	return *this;
}

SimpleEvent& SimpleEvent::operator=(const SharedHandle& rhs)
{
	{CriticalSectionGuard g(cs_);
		handle_ = rhs;
	}
	return *this;
}


SimpleEvent::operator HANDLE() const
{
	HANDLE retVal = 0;
	{CriticalSectionGuard g(cs_);
		retVal = handle_.get();
	}
	return retVal;
}

bool SimpleEvent::create(bool manualReset, bool initialState, const char* name)
{
	bool retVal = false;
	{CriticalSectionGuard g(cs_);
		handle_.reset(::CreateEvent(0, // No security attributes.
									manualReset,
									initialState,
									name),
					  SharedHandleDeleter());
		SHOW_LAST_ERROR((0 != handle_), "SimpleEvent::create", "::CreateEvent");
		retVal = (0 != handle_);
	}
	return retVal;
}

void SimpleEvent::close(void)
{
	{CriticalSectionGuard g(cs_);
		handle_.reset();
	}
}

bool SimpleEvent::set(void)
{
	bool retVal = false;
	{CriticalSectionGuard g(cs_);
		retVal = ::SetEvent(handle_.get()) ? true : false;
		SHOW_LAST_ERROR(retVal, "SimpleEvent::set", "::SetEvent");
	}
	return retVal;
}

bool SimpleEvent::reset(void)
{
	bool retVal = false;
	{CriticalSectionGuard g(cs_);
		retVal = ::ResetEvent(handle_.get()) ? true : false;
		SHOW_LAST_ERROR(retVal, "SimpleEvent::reset", "::ResetEvent");
	}
	return retVal;
}

bool SimpleEvent::wait(DWORD timeout) const
{
	// Don't put blocking call in critical section.
	HANDLE h = 0;
	{CriticalSectionGuard g(cs_);
		h = handle_.get();
	}
	DWORD waitResult = ::WaitForSingleObject(h, timeout); 
	SHOW_LAST_ERROR((WAIT_FAILED != waitResult), "SimpleEvent::wait", "::WaitForSingleObject");
	return (WAIT_OBJECT_0 == waitResult);
}

}
